<template>
  <p>App</p>
  <!-- ref在模板页面中直接使用 -->
  <p>{{ num }}</p>
  <p>{{ oddOrEven }}</p>
  <button @click="handleClick">更新</button>
  <p v-for="(value, key) in person" :key="key">{{ key }} - {{ value }}</p>
  <button @click="setAge">更新</button>

  <Child :num="num" @setNum="handleClick" ref="child" />
</template>

<script lang="ts">
import {
  ref,
  reactive,
  watch,
  computed,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
} from "vue";
import Child from "./Child.vue";

export default {
  name: "App",
  components: { Child },
  // 组合式API Composition API
  setup() {
    // 初始化渲染时就会触发，相当于beforeCreate和created
    console.log("setup");
    // 定义一个和 ref="xxx" 名称一样的ref数据，并暴露出去
    // vue就会将组件实例对象/DOM元素绑定到这个ref数据上
    const child = ref();

    onUpdated(() => {
      console.log("onUpdated");
    });

    onBeforeUnmount(() => {
      console.log("onBeforeUnmount");
    });

    onMounted(() => {
      console.log(child.value);
      console.log("mounted 111");
    });
    onMounted(() => {
      console.log("mounted 222");
    });
    onMounted(() => {
      console.log("mounted 333");
    });

    // 定义单个响应式数据 ref
    /***************** xxx功能 *****************/
    // const num = ref<number>(0);
    const num = ref(0);

    // 定义方法 methods
    const handleClick = () => {
      // console.log(this, num.value); // undefined
      // ref数据在js中必须通过 xxx.value 去读或写
      num.value++;
    };
    // 定义多个响应式数据 reactive
    // interface Person {
    //   name: string;
    //   age: number;
    // }
    // const person = reactive<Person>({
    //   name: "jack",
    //   age: 18,
    // });
    /***************** yyy功能 *****************/
    const person = reactive({
      name: "jack",
      age: 18,
    });

    const setAge = () => {
      // reactive定义的数据可以直接操作
      person.age++;
      // 不能直接赋值, 会失去响应式
      // person = {}
    };

    watch(
      num,
      (newVal, oldVal) => {
        console.log(newVal, oldVal);
      },
      {
        // deep: true,
        // immediate: true
      }
    );

    watch(person, (newVal, oldVal) => {
      // 新值和旧值相等
      console.log(newVal, oldVal);
    });

    watch(
      // 想要监视reactive数据中某个属性，必须写成函数形式
      () => person.age,
      (newVal, oldVal) => {
        console.log(newVal, oldVal);
      }
    );

    // 只读计算属性
    const oddOrEven = computed(() => {
      return (num.value & 1) === 1 ? "奇数" : "偶数";
    });
    // 可读可写的计算属性
    const xxx = computed({
      get() {},
      set() {},
    });

    // 暴露出去
    // 都会添加到组件实例对象上
    return {
      num,
      handleClick,
      person,
      setAge,
      oddOrEven,
      child,
    };
  },
};
</script>

<style scoped></style>
